package com.example.mydianping.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.example.mydianping.dto.Result;
import com.example.mydianping.dto.UserDTO;
import com.example.mydianping.mapper.BlogMapper;
import com.example.mydianping.mapper.FollowMapper;
import com.example.mydianping.mapper.UserMapper;
import com.example.mydianping.pojo.Blog;
import com.example.mydianping.pojo.BlogsFeedResult;
import com.example.mydianping.pojo.User;
import com.example.mydianping.service.BlogService;
import com.example.mydianping.service.FollowService;
import com.example.mydianping.utils.UserHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

@Service
public class BlogServiceImpl implements BlogService {

    @Autowired
    private BlogMapper blogMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private UserMapper userMapper;
    @Resource
    private FollowMapper followMapper;

    @Override
    public Result saveBlag(Blog blog) {
        if(blog == null){
            return Result.fail("博文状态异常");
        }
        int insert = blogMapper.insert(blog);
        if(insert == 0){
            return Result.fail("存入数据失败");
        }
        //TODO 将博文 id 推送给所有粉丝
        UserDTO user = UserHolder.getUser();
        if(user == null){
            return Result.fail("用户未登录");
        }
        //在tb_follow表中查询 user_id 为当前用户的所有粉丝
        List<Long> fans = followMapper.getFans(user.getId());
        //将博文 id 发送给所有粉丝的消息箱子（即redis的key）
        for (Long fan : fans) {
            String feedKey = "blog:feed:"+fan;
            stringRedisTemplate.opsForZSet().add(feedKey,Long.toString(user.getId()), System.currentTimeMillis());
        }
        return Result.ok(blog);
    }

    @Override
    public Blog queryBlog(Long id) {
        return blogMapper.selectById(id);
    }

    @Override
    @Transactional
    public Result updateBlog(Long id) {
        //拿到登录的用户信息
        UserDTO user = UserHolder.getUser();
        if(user == null){
            return Result.fail("用户登录信息失效，请登录后重试");
        }
        //判断该博文下是否已经有该用户的点赞信息,没有就点赞，有就取消点赞
        Double score = stringRedisTemplate.opsForZSet().score("liked:blog:" + id, Long.toString(user.getId()));
        if(score == null){
            //如果该用户没有给该博文点赞过，就将该博文的点赞加一，并将该用户加入这个博文的 Key 下
            Boolean aBoolean = blogMapper.likeAddOne(id);
            if(aBoolean != null && aBoolean){
                //比opsForSet(0 多一个 score 参数，这里用时间戳作为 score
                stringRedisTemplate.opsForZSet().add("liked:blog:" + id, Long.toString(user.getId()),System.currentTimeMillis());
            }
            return Result.ok("成功点赞！");
        }else{
            //反之，减一，移除
            Boolean aBoolean = blogMapper.likeRemoveOne(id);
            if(aBoolean != null && aBoolean)
            stringRedisTemplate.opsForZSet().remove("liked:blog:" + id, Long.toString(user.getId()));
            return Result.ok("点赞已取消");
        }
    }

    @Override
    public Result likes(Long id) {
        //根据id拿到保存到 redis 中的前五条用户信息
        Set<String> range = stringRedisTemplate.opsForZSet().range("liked:blog:" + id, 0, 4);//左闭右闭
        //根据用户id封装用户信息到集合中
        if(range == null){
            return Result.fail("没有点赞用户");
        }
        List<UserDTO> list = new ArrayList<>();
        for(String s : range){
            User user = userMapper.selectById(Long.parseLong(s));
            UserDTO userDTO = BeanUtil.copyProperties(user,UserDTO.class);
            list.add(userDTO);
        }
        return Result.ok(list);
    }

    @Override
    public Result getBlogs(Long id) {
        List<Blog> allBlogs = blogMapper.getAllBlogs(id);
        return Result.ok(allBlogs);
    }

    @Override
    public Result getFeed(Long max,Integer offset) {
        UserDTO user = UserHolder.getUser();
        if(user == null){
            return Result.fail("用户登录信息失效，请登录后重试");
        }
        //拿到消息箱分页处理后的博文id
        String feedKey = "blog:feed:"+user.getId();
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores(feedKey, 0, max, offset, 3);
        //每一个 tuples 都装了 一个 value 和一个 score
        if(typedTuples == null || typedTuples.size() == 0){
            return Result.fail("未关注任何用户");
        }
        long min = System.currentTimeMillis();
        int save = 1;
        List<Blog> blogs = new ArrayList<>();
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            //将博文信息封装到集合中，并拿到当前查询的最小时间戳，计算最小时间戳的元素个数
            Blog blog = blogMapper.selectById(Long.parseLong(tuple.getValue()));
            blogs.add(blog);
            long time = tuple.getScore().longValue();
            if(time == min){
                save++;
            }else{
                min = time;
                save = 1;
            }
        }
        BlogsFeedResult blogsFeedResult = new BlogsFeedResult();
        blogsFeedResult.setBlogs(blogs);
        blogsFeedResult.setMax(min);
        blogsFeedResult.setOffset(save);
        return Result.ok(blogsFeedResult);
    }
}
